package com.ml.loan.common.redis;


import com.ml.loan.common.utils.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.BitSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class RedisService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 获取真实redis前缀
     *
     * @Author Mickey
     * @Date 2021/3/5 18:45
     **/
    public String getRealKey(iKeyPrefix prefix, String key) {
        return prefix.getPrefix() + key;
    }

    /**
     * 设置对象
     *
     * @Author Mickey
     * @Date 2021/2/12 23:50
     **/
    public <T> boolean set(iKeyPrefix prefix, String key, T value) {
        String str = RedisUtil.beanToString(value);
        if (str == null || str.length() == 0) {
            return false;
        }
        String realKey = getRealKey(prefix, key);
        long seconds = prefix.expireSeconds();
        if (seconds <= 0) {
            stringRedisTemplate.opsForValue().set(realKey, str);
        } else {
            stringRedisTemplate.opsForValue().set(realKey, str, seconds, TimeUnit.SECONDS);
        }
        return true;
    }

    /**
     * 获取对象
     *
     * @Author Mickey
     * @Date 2021/2/12 23:51
     **/
    public <T> T get(iKeyPrefix prefix, String key, Class<T> clazz) {
        String realKey = getRealKey(prefix, key);
        String str = stringRedisTemplate.opsForValue().get(realKey);
        return RedisUtil.stringToBean(str, clazz);
    }

    /**
     * 删除单个对象
     *
     * @Author Mickey
     * @Date 2021/2/12 23:52
     **/
    public boolean delete(iKeyPrefix prefix, String key) {
        String realKey = getRealKey(prefix, key);
        return stringRedisTemplate.delete(realKey);
    }

    /**
     * 删除匹配对象（多个）
     *
     * @Author Mickey
     * @Date 2021/2/12 23:52
     **/
    public long deleteByPattern(String keyPattern) {
        Set<String> keys = stringRedisTemplate.keys(keyPattern);
        return stringRedisTemplate.delete(keys);
    }

    /**
     * 根据前缀删除
     *
     * @Author Mickey
     * @Date 2021/2/12 23:53
     **/
    public long deleteAllByKey(iKeyPrefix prefix) {
        String realKey = getRealKey(prefix, "*");
        return deleteByPattern(realKey);
    }

    /**
     * 获取剩余过期时间（秒）
     *
     * @Author Mickey
     * @Date 2021/2/12 23:54
     **/
    public Long getExpire(iKeyPrefix prefix, String key) {
        String realKey = getRealKey(prefix, key);
        return stringRedisTemplate.getExpire(realKey, TimeUnit.SECONDS);
    }

    /**
     * 根据前缀配置设置过期时间
     *
     * @Author Mickey
     * @Date 2021/2/12 23:55
     **/
    public boolean setExpire(iKeyPrefix prefix, String key) {
        String realKey = getRealKey(prefix, key);
        return stringRedisTemplate.expire(realKey, prefix.expireSeconds(), TimeUnit.SECONDS);
    }


    /**
     * 根据前缀增加1
     *
     * @Author Mickey
     * @Date 2021/2/12 23:56
     **/
    public long incrementOne(iKeyPrefix prefix, String key) {
        return increment(prefix, key, null);
    }

    /**
     * 根据前缀减少1
     *
     * @Author Mickey
     * @Date 2021/2/12 23:56
     **/
    public long decrementOne(iKeyPrefix prefix, String key) {
        return decrement(prefix, key, null);
    }

    /**
     * 根据前缀增加值
     *
     * @Author Mickey
     * @Date 2021/2/12 23:56
     **/
    public long increment(iKeyPrefix prefix, String key, Long addValue) {
        addValue = Optional.ofNullable(addValue).orElse(1L);
        String realKey = getRealKey(prefix, key);
        long count = stringRedisTemplate.boundValueOps(realKey).increment(addValue);
        long seconds = prefix.expireSeconds();
        if (seconds > 0) {
            setExpire(prefix, key);
        }
        return count;
    }

    /**
     * 根据前缀减少值
     *
     * @Author Mickey
     * @Date 2021/2/12 23:56
     **/
    public long decrement(iKeyPrefix prefix, String key, Long reduceValue) {
        reduceValue = Optional.ofNullable(reduceValue).orElse(1L);
        String realKey = getRealKey(prefix, key);
        long count = stringRedisTemplate.boundValueOps(realKey).decrement(reduceValue);
        long seconds = prefix.expireSeconds();
        if (seconds > 0) {
            setExpire(prefix, key);
        }
        return count;
    }

    /**
     * 设置bit
     *
     * @Author Mickey
     * @Date 2021/2/13 0:06
     **/
    public void setBit(iKeyPrefix prefix, String key, long offset) {
        String realKey = getRealKey(prefix, key);
        stringRedisTemplate.opsForValue().setBit(realKey, offset, true);
        long seconds = prefix.expireSeconds();
        if (seconds > 0) {
            setExpire(prefix, key);
        }
    }

    /**
     * 获取bit某个位置的状态
     *
     * @Author Mickey
     * @Date 2021/2/13 0:06
     **/
    public boolean getBit(iKeyPrefix prefix, String key, long offset) {
        return stringRedisTemplate.opsForValue().getBit(getRealKey(prefix, key), offset);
    }

    /**
     * 获取bitset
     *
     * @Author Mickey
     * @Date 2021/2/13 0:07
     **/
    public BitSet getBitSet(iKeyPrefix prefix, String key) {
        return BitSet.valueOf(stringRedisTemplate.opsForValue().get(getRealKey(prefix, key)).getBytes());
    }

    /**
     * 获取bitcount
     *
     * @Author Mickey
     * @Date 2021/2/13 0:08
     **/
    public long bitCount(iKeyPrefix prefix, String key) {
        String realKey = getRealKey(prefix, key);
        return stringRedisTemplate.execute((RedisCallback<Long>) con -> con.bitCount(realKey.getBytes()));
    }

    /**
     * 设置hash属性
     *
     * @Author Mickey
     * @Date 2021/2/13 0:09
     **/
    public void putHash(iKeyPrefix prefix, String key, String name, String value) {
        stringRedisTemplate.opsForHash().put(getRealKey(prefix, key), name, value);
    }

    /**
     * 获取hash属性
     *
     * @Author Mickey
     * @Date 2021/2/13 0:09
     **/
    public Object getHash(iKeyPrefix prefix, String key, String name) {
        return stringRedisTemplate.opsForHash().get(getRealKey(prefix, key), name);
    }

    /**
     * 添加Set元素
     *
     * @Author Mickey
     * @Date 2021/2/13 0:11
     **/
    public Long addSet(iKeyPrefix prefix, String key, String... value) {
        String realKey = getRealKey(prefix, key);
        Long n = stringRedisTemplate.opsForSet().add(realKey, value);
        long seconds = prefix.expireSeconds();
        if (seconds > 0) {
            setExpire(prefix, key);
        }
        return n;
    }

    /**
     * 移除Set元素
     *
     * @Author Mickey
     * @Date 2021/2/13 0:12
     **/
    public Long removeSet(iKeyPrefix prefix, String key, String... value) {
        String realKey = getRealKey(prefix, key);
        return stringRedisTemplate.opsForSet().remove(realKey, value);
    }

    /**
     * 判断Set是否存在元素
     *
     * @Author Mickey
     * @Date 2021/2/13 0:12
     **/
    public boolean isMemberBySet(iKeyPrefix prefix, String key, String value) {
        String realKey = getRealKey(prefix, key);
        return stringRedisTemplate.opsForSet().isMember(realKey, value);
    }

    /**
     * 统计Set中的数量
     *
     * @Author Mickey
     * @Date 2021/2/13 0:13
     **/
    public Long sizeBySet(iKeyPrefix prefix, String key) {
        return stringRedisTemplate.opsForSet().size(getRealKey(prefix, key));
    }

    /**
     * list添加单个元素（左）
     *
     * @Author Mickey
     * @Date 2021/2/13 0:18
     **/
    public Long listPushLeft(iKeyPrefix prefix, String key, String value) {
        String realKey = getRealKey(prefix, key);
        long seconds = prefix.expireSeconds();
        Long l = stringRedisTemplate.opsForList().leftPush(realKey, value);
        if (seconds > 0 && l == 1) {
            setExpire(prefix, key);
        }
        return l;
    }

    /**
     * list添加多个元素（左）
     *
     * @Author Mickey
     * @Date 2021/2/13 0:18
     **/
    public Long listPushLeftAll(iKeyPrefix prefix, String key, String... value) {
        String realKey = getRealKey(prefix, key);
        long seconds = prefix.expireSeconds();
        Long l = stringRedisTemplate.opsForList().leftPushAll(realKey, value);
        if (seconds > 0 && l == 1) {
            setExpire(prefix, key);
        }
        return l;
    }

    /**
     * list弹出元素（左）
     *
     * @Author Mickey
     * @Date 2021/2/13 0:18
     **/
    public String listPopLeft(iKeyPrefix prefix, String key) {
        String realKey = getRealKey(prefix, key);
        return stringRedisTemplate.opsForList().leftPop(realKey);
    }

    /**
     * list弹出元素（右）
     *
     * @Author Mickey
     * @Date 2021/2/13 0:18
     **/
    public String listPopRight(iKeyPrefix prefix, String key) {
        String realKey = getRealKey(prefix, key);
        return stringRedisTemplate.opsForList().rightPop(realKey);
    }

    /**
     * list移除元素
     *
     * @param prefix
     * @param key
     * @param value
     * @author caozx
     * @date 2021/4/21 19:16
     **/
    public long listRemove(iKeyPrefix prefix, String key, String value) {
        String realKey = getRealKey(prefix, key);
        return stringRedisTemplate.opsForList().remove(realKey, 0, value);
    }

    /**
     * list添加单个元素（右）
     *
     * @Author Mickey
     * @Date 2021/2/13 0:18
     **/
    public Long listPushRight(iKeyPrefix prefix, String key, String value) {
        String realKey = getRealKey(prefix, key);
        long seconds = prefix.expireSeconds();
        Long l = stringRedisTemplate.opsForList().rightPush(realKey, value);
        if (seconds > 0 && l > 0) {
            setExpire(prefix, key);
        }
        return l;
    }

    /**
     * list添加多个元素（右）
     *
     * @Author Mickey
     * @Date 2021/2/13 0:18
     **/
    public Long listPushRight(iKeyPrefix prefix, String key, String... value) {
        String realKey = getRealKey(prefix, key);
        long seconds = prefix.expireSeconds();
        Long l = stringRedisTemplate.opsForList().rightPushAll(realKey, value);
        if (seconds > 0 && l > 0) {
            setExpire(prefix, key);
        }
        return l;
    }

    /**
     * 判断数据是否在list中
     *
     * @Author Mickey
     * @Date 2021/3/22 21:45
     **/
    public boolean listExists(iKeyPrefix prefix, String key, String value) {
        String realKey = getRealKey(prefix, key);
        List<String> datas = stringRedisTemplate.opsForList().range(realKey, 0, -1);
        boolean exists = datas.stream().filter(d -> d.equals(value)).collect(Collectors.toSet()).isEmpty();
        return !exists;
    }

    /**
     * list长度
     *
     * @param prefix
     * @param key
     * @return
     */
    public Long listSize(iKeyPrefix prefix, String key) {
        String realKey = getRealKey(prefix, key);
        return stringRedisTemplate.opsForList().size(realKey);
    }

    /**
     * 查看list所有数据
     *
     * @param prefix
     * @param key
     * @return
     */
    public List<String> listAllData(iKeyPrefix prefix, String key) {
        String realKey = getRealKey(prefix, key);
        return stringRedisTemplate.opsForList().range(realKey, 0, -1);
    }

    public String getStringValue(String key) {
        return stringRedisTemplate.opsForValue().get(key);
    }

    public boolean deleteByKey(String key) {
        return stringRedisTemplate.delete(key);
    }
}
